package com.nulldev.util.graphics.renderIt.api;

import java.util.Map;

import javax.swing.JFrame;

import com.nulldev.util.JVM.JVM;
import com.nulldev.util.JVM.reflections.Reflections;
import com.nulldev.util.graphics.renderIt.api.core.IRenderCanvas;
import com.nulldev.util.graphics.renderIt.api.core.renderItOutputType;
import com.nulldev.util.internal.backport.concurrency9.Maps;
import com.nulldev.util.manage.Version;
import com.nulldev.util.manage.experiments.Experiments;
import com.nulldev.util.osAPI.OS;

public class renderItAPI {
	public static final Version VERSION = new Version(0, 1, 37);

	private static final boolean ENBALE_EXPERIMENTAL_BACKENDS = Experiments.get("renderit://enable-experimental/").isActive();
	private static final String RIT_PLATFORM_NITROUS = "nitrous";

	/* RIT_AWT_FRAME */

	private static final Map<String, String> RIT_AWT_FRAME_PLATFORM_EXPERIMENTAL = Maps.of(new Object[][]
		{
				{ "skija", "com.nulldev.util.graphics.renderIt.ginterfaces.skija.SkijaRenderPane" },
				{ "nitrous2", "com.nulldev.util.graphics.renderIt.ginterfaces.nitrous2.Nitrous2RenderPane" } });

	private static final Map<String, String> RIT_AWT_FRAME_PLATFORM_WINDOWS = Maps.of(new Object[][]
		{
				{ "nitrous", "com.nulldev.util.graphics.renderIt.ginterfaces.nitrous.NitrousRenderPane" },
				{ "swing", "com.nulldev.util.graphics.renderIt.ginterfaces.swing.SwingRenderPane" },
				{ "marlin", "com.nulldev.util.graphics.renderIt.ginterfaces.marlin.MarlinRenderPane" } });

	private static final Map<String, String> RIT_AWT_FRAME_PLATFORM_UNIX = Maps.of(new Object[][]
		{
				{ "swing", "com.nulldev.util.graphics.renderIt.ginterfaces.swing.SwingRenderPane" },
				{ "marlin", "com.nulldev.util.graphics.renderIt.ginterfaces.marlin.MarlinRenderPane" } });

	private static final Map<String, String> RIT_AWT_FRAME_PLATFORM_OTHER = Maps.of(new Object[][]
		{
				{ "swing", "com.nulldev.util.graphics.renderIt.ginterfaces.swing.SwingRenderPane" },
				{ "marlin", "com.nulldev.util.graphics.renderIt.ginterfaces.marlin.MarlinRenderPane" } });

	private static final Map<String, String> RIT_AWT_FRAME_PLATFORM;

	static {
		switch (OS.get()) {
			case BSD:
			case Linux:
				RIT_AWT_FRAME_PLATFORM = RIT_AWT_FRAME_PLATFORM_UNIX;
				break;
			case Windows:
				RIT_AWT_FRAME_PLATFORM = RIT_AWT_FRAME_PLATFORM_WINDOWS;
				break;
			default:
				RIT_AWT_FRAME_PLATFORM = RIT_AWT_FRAME_PLATFORM_OTHER;
				break;
		}
	}

	public static IRenderCanvas make_instance(final renderItOutputType type) {
		return make_instance(type, null);
	}

	public static IRenderCanvas make_instance(final renderItOutputType type, final JFrame jfr) {
		switch (type) {
			case RIT_OUTPUT_TYPE_SWING_FRAME:
			case RIT_OUTPUT_TYPE_AWT_FRAME: {
				for (final Map.Entry<String, String> candidate : (ENBALE_EXPERIMENTAL_BACKENDS ? RIT_AWT_FRAME_PLATFORM_EXPERIMENTAL : RIT_AWT_FRAME_PLATFORM)
						.entrySet()) {
					try {
						if (candidate.getKey().equals(RIT_PLATFORM_NITROUS) && JVM.version() > 1.8f) {
							continue;
						} else if (Reflections.is(candidate.getValue())) {
							return (IRenderCanvas) Reflections.get(candidate.getValue()).getConstructor(JFrame.class).newInstance(jfr);
						} else {
							JVM.println("[renderIt] Failed to find '" + candidate.getValue() + "', skipping.");
							continue;
						}
					} catch (Exception ex) {
						JVM.println(" - " + candidate.getKey() + " failed to init.");
						JVM.errorln(ex);
					}
				}
				throw new UnsupportedOperationException("Failed to init a working canvas!");
			}
			default:
				throw new UnsupportedOperationException("Unsupported output type: " + type);
		}
	}
}
